#include "stdafx.h"

#include "VertexBuffer.h"

using namespace Hiranipra;
using namespace Hiranipra::Platform;
using namespace Hiranipra::Platform::Graphics;

// Could use STREAM_DRAW instead of STATIC_DRAW if the # of draws will be small

VertexBuffer::VertexBuffer( const BufferFlags flags, VertexDeclaration* vertexDecl, const uint32 elementCount, const void* buffer ) :
	IVertexBuffer( flags, vertexDecl, elementCount )
{
	glGenBuffers( 1, &_bufferId );
	
	if( buffer != NULL )
	{
		glBindBuffer( GL_ARRAY_BUFFER, _bufferId );

		int usage = ( ( _flags & BufferDynamic ) == BufferDynamic ) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW;
		glBufferData( GL_ARRAY_BUFFER, elementCount * _elementSize, buffer, usage );
	}
}

VertexBuffer::~VertexBuffer()
{
	glDeleteBuffers( 1, &_bufferId );
	_bufferId = 0;
}

bool VertexBuffer::Upload()
{
	if( this->IBuffer::Upload() == false )
		return false;

	// TODO: upload

	return true;
}

bool VertexBuffer::GetData( void* buffer, uint32 startIndex, uint32 elementCount ) const
{
	DASSERT( _isLocked == true, "Attempt to GetData() while not locked" );
	if( _isLocked == false )
		return false;
	bool lockedForRead = ( ( _lockFlags & LockRead ) == LockRead );
	DASSERT( lockedForRead == true, "Attempt to GetData() without read lock" );
	if( lockedForRead == false )
		return false;

	glGetBufferSubData( GL_ARRAY_BUFFER, startIndex * _elementSize, elementCount * _elementSize, buffer );
	return true;
}

void VertexBuffer::SetData( const void* buffer, uint32 startIndex, uint32 elementCount, bool discard )
{
	DASSERT( _isLocked == true, "Attempt to SetData() while not locked" );
	if( _isLocked == false )
		return;
	bool lockedForWrite = ( ( _lockFlags & LockWrite ) == LockWrite );
	DASSERT( lockedForWrite == true, "Attempt to SetData() without write lock" );
	if( lockedForWrite == false )
		return;

	int usage = ( ( _flags & BufferDynamic ) == BufferDynamic ) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW;

	glBindBuffer( GL_ARRAY_BUFFER, _bufferId );

	uint32 totalSize = _elementCount * _elementSize;
	if( discard == true )
		glBufferData( GL_ARRAY_BUFFER, totalSize, NULL, usage );
	
	if( ( startIndex > 0 ) || ( elementCount < _elementCount ) )
	{
		// Sub update
		glBufferSubData( GL_ARRAY_BUFFER, startIndex * _elementSize, elementCount * _elementSize, buffer );
	}
	else
	{
		// Full update
		glBufferData( GL_ARRAY_BUFFER, totalSize, buffer, usage );
	}
	
	_isDirty = true;
}
